package cn.sc.summer.gateway.webfilter;

import cn.hutool.core.util.StrUtil;
import cn.sc.summer.gateway.exception.CommonException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.sc.summer.constant.gateway.GatewayConstant;
import cn.sc.summer.constant.token.AuthProperties;
import cn.sc.summer.constant.util.MatchUtil;
import cn.sc.summer.constant.model.Result;
import cn.sc.summer.redis.util.RedisHelper;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

/**
 * 类名：图形验证码校验拦截器
 *
 * @author a-xin
 * @date 2023/8/18 11:02
 */
@Slf4j
@Component
@AllArgsConstructor
@Order(-101)
public class ValidateCodeFilter implements WebFilter {

    private final ObjectMapper objectMapper;

    @Resource
    private AuthProperties authProperties;

    @Override
    @NonNull
    public Mono<Void> filter(@NonNull ServerWebExchange exchange, WebFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();

        if (!MatchUtil.anyMatchValue(path, authProperties.getImageCode())) {
            return chain.filter(exchange);
        }
        try {
            //校验验证码
            checkCode(request);
        } catch (Exception e) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
            try {
                return response.writeWith(Mono.just(
                        response.bufferFactory().wrap(objectMapper.writeValueAsBytes(Result.fail(e.getMessage())))));
            } catch (JsonProcessingException e1) {
                throw new CommonException("Object output exception: ", e1);
            }
        }
        return chain.filter(exchange);
    }

    /**
     * 校验图形验证码，code：验证码，randomKey：校验唯一key
     *
     * @param request 请求体
     */
    @SneakyThrows
    private void checkCode(ServerHttpRequest request) {

        String path = request.getPath().toString();
        String code = request.getHeaders().getFirst("imageCode");
        String randomKey = request.getHeaders().getFirst("imageRandomKey");

        if (StrUtil.isBlank(code) || StrUtil.isBlank(randomKey)) {
            log.error("==> The path : {} , The graphic captcha cannot be empty！", path);
            throw new CommonException("The graphic captcha cannot be empty！");
        }

        if (!RedisHelper.hasKey(GatewayConstant.CODE_KEY + randomKey)) {
            log.error("==> The path : {} , The graphic captcha has expired, please update！", path);
            throw new CommonException("The graphic captcha has expired, please update！");
        }

        String redisCode = (String) RedisHelper.get(GatewayConstant.CODE_KEY + randomKey);
        if (StrUtil.isBlank(redisCode)) {
            RedisHelper.del(GatewayConstant.CODE_KEY + randomKey);
            log.error("==> The path : {} , The graphic captcha has expired, please update！", path);
            throw new CommonException("The graphic captcha has expired, please update！");
        }

        if (!code.equals(redisCode)) {
            RedisHelper.del(GatewayConstant.CODE_KEY + randomKey);
            log.error("==> The path : {} , Graphics captcha error！", path);
            throw new CommonException("Graphics captcha error！");
        }

        RedisHelper.del(GatewayConstant.CODE_KEY + randomKey);

    }
}

